﻿using System.Collections.Concurrent;

namespace ConsoleApp;

/// <summary>
/// 分区集合（Partitioned Collections）Lock
/// 分区集合是一种将集合分割成多个部分，每个部分有自己的锁，这样可以减少锁的竞争，提高并发性能。实现分区集合需要手动管理多个锁和分区逻辑，这通常会增加代码复杂度。
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
public class PartitionedDictionary<TKey, TValue> where TKey : notnull
{
    private readonly int _partitionsCount;
    private readonly object[] _locks;
    private readonly Dictionary<TKey, TValue>[] _partitions;

    // 通常在高并发场景下性能更好，因为它们使用了更细粒度的锁或无锁算法，减少了锁的竞争
    public void Demo()
    {
        var dictionary = new ConcurrentDictionary<int, string>();

        // 添加或更新元素
        dictionary.AddOrUpdate(1, "value1", (key, oldValue) => "newValue");

        // 读取元素
        if (dictionary.TryGetValue(1, out string value))
        {
            Console.WriteLine(value);
        }
    }
    
    public PartitionedDictionary(int partitionsCount)
    {
        _partitionsCount = partitionsCount;
        _locks = new object[partitionsCount];
        _partitions = new Dictionary<TKey, TValue>[partitionsCount];

        for (var i = 0; i < partitionsCount; i++)
        {
            _locks[i] = new object();
            _partitions[i] = new Dictionary<TKey, TValue>();
        }
    }

    private int GetPartitionIndex(TKey key)
    {
        return (key.GetHashCode() & int.MaxValue) % _partitionsCount;
    }

    public void AddOrUpdate(TKey key, TValue value)
    {
        var index = GetPartitionIndex(key);
        lock (_locks[index])
        {
            _partitions[index][key] = value;
        }
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        var index = GetPartitionIndex(key);
        lock (_locks[index])
        {
            return _partitions[index].TryGetValue(key, out value);
        }
    }
}